% -------------------------------------------------------------------------
% MAIN
% -------------------------------------------------------------------------

global EPOCHS;
global LAYERS;
global ETA;
global k_eta_adap;

format long;
constants;

load patterns;

training_patterns = patterns{1}(1:3,:);
S_training_patterns = normalize_outputs(patterns{1}(4,:));
testing_patterns = patterns{2}(1:3,:);
S_testing_patterns = normalize_outputs(patterns{2}(4,:));

weights = matrix_weights();
alpha = ALPHA;

k_eta_adap = 0;
f = 1;

figure1 = figure('XVisual', '0x24 (TrueColor, depth 24, RGB mask 0xff0000 0xff00 0x00ff)');
figure2 = figure('XVisual', '0x24 (TrueColor, depth 24, RGB mask 0xff0000 0xff00 0x00ff)');

memorization = zeros(1,1);
generalization = zeros(1,1);

step = 10;
samples = EPOCHS/step;

axes1 = axes('Parent', figure1);
xlim(axes1, [0 samples]);
ylim(axes1, [0 5]);
box(axes1, 'on');
hold(axes1, 'all');

axes2 = axes('Parent', figure2);
xlim(axes2, [-2 2]);
ylim(axes2, [-2 2]);
zlim(axes2, [-2 2]);


xlabel(axes1, 'Epocas (x10)');
ylabel(axes1, 'Error de memorizacion y generalizacion');

for epoch = 1:EPOCHS
    shuffle_p = shuffle_patterns(training_patterns, S_training_patterns);
    training_patterns = shuffle_p(1:3,:);
    S_training_patterns = shuffle_p(4,:);
    
    for i = 1:length(training_patterns)
        ret = feed_forward(weights, training_patterns(:,i), S_training_patterns(i));
        deltas = ret{1};
        h = ret{2};
        delta_weights = back_propagation(weights, deltas, h, training_patterns(:,i));
        for j = 1:length(LAYERS)
            weights{j} = weights{j} + delta_weights{j};
            if i > 1
                weights{j} = weights{j} + alpha * previous_weights{j};
            end
        end
        previous_weights = weights;
    end

    o = compute_outputs(weights, testing_patterns);
    m = compute_outputs(weights, training_patterns);
    cost = cost_function(S_testing_patterns, o);
    costM = cost_function(S_training_patterns, m);

    if mod(epoch, step) == 0
        memorization(f) = cost;
        generalization(f) = costM;
        plot(memorization, 'b', 'Parent', axes1);
        plot(generalization, 'g', 'Parent', axes1);
        auxx = [training_patterns(2,:), testing_patterns(2,:)];
        auxy = [training_patterns(3,:), testing_patterns(3,:)];
        auxz = [m, o];
        plot3(auxx, auxy, auxz, '.', 'Parent', axes2);
        drawnow
        f = f + 1;
    end

    msg = sprintf('Cost G: %g | Cost M: %g | ETA: %g | Epoch: %d', cost, costM, ETA, epoch);
    disp(msg);

    if epoch > 1
        ETA = adaptative_eta(cost, previous_cost);
        if cost > previous_cost && ALPHA > 0
            alpha = 0;
            weights = previous_weights_epoch;
        else
            alpha = ALPHA;
        end
    end

    previous_cost = cost;
    previous_weights_epoch = weights;

end

msg = sprintf('Epochs limit reached! Cost: %g', cost);
disp(msg);
